package org.admanager.soa.plugin.popup.actions;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.admanager.soa.plugin.Activator;
import org.admanager.soa.plugin.util.KermetaRunner;
import org.admanager.soa.plugin.util.ValidationDetailDialog;
import org.admanager.soadmanagement.plugin.soadmanagement.ComponentMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ComponentReferenceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ComponentServiceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.CompositeMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ReferenceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.RootMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ServiceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.util.soadmanagementSwitch;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ocl.examples.xtext.oclinecore.validation.OCLinEcoreEObjectValidator;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

import fr.irisa.triskell.eclipse.console.EclipseConsole;
import fr.irisa.triskell.eclipse.console.IOConsole;

public class ExtractionAndValidationActionDelegate implements
		IObjectActionDelegate {
	private ISelection selection;
	IWorkbenchPart targetPart;
	MultiStatus fianlInfo;
	MultiStatus infoMapping;
	public ExtractionAndValidationActionDelegate() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void run(IAction action) {
		// TODO Auto-generated method stub
		if (selection instanceof IStructuredSelection) {
			Object obj = (Object) ((IStructuredSelection) selection)
					.getFirstElement();
			if (obj instanceof IFile) {
				//Declare a list of pattern view name corresponding to the SCA model
				List<String> arrPatternViewName = new ArrayList<String>();
				//Transformation
				// Get file
				IFile inputModelFile = (IFile) obj;
				URI inputModel = URI.createURI(inputModelFile.getLocationURI()
						.toString());
				// Get the current project
				IProject myProject = inputModelFile.getProject();

				// Get the URI for the output model
				IFolder patternViewFolder = myProject.getFolder("PatternView");
				if (!patternViewFolder.exists())
					try {
						patternViewFolder.create(true, true,
								new NullProgressMonitor());
					} catch (CoreException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				/*
				 * IFolder patternFolder =
				 * patternViewFolder.getFolder(inputModelFile
				 * .getName().replace("soapattern", "")); if
				 * (!patternFolder.exists()) try { patternFolder.create(true,
				 * true, new NullProgressMonitor()); } catch (CoreException e1)
				 * { // TODO Auto-generated catch block e1.printStackTrace(); }
				 */
				// String metaPatternName =
				// getPatternModelURI(inputModelFile).lastSegment().replace(".soapattern","");
				IFolder mappingFolder = myProject.getFolder("SCAMapping");
				try {
					for (IResource f : mappingFolder.members()) {
						if (f instanceof IFile)
							if (f.getFileExtension().endsWith("mapping")) {
								String simplifiedSCAModelName = getSimplifiedSCAModelURI(
										(IFile) f).lastSegment().replace(
										".simplifiedsca", "");
								if (simplifiedSCAModelName.equals(inputModel
										.lastSegment().replace(
												".simplifiedsca", ""))) {
									URI mappingModel = URI.createURI(f
											.getLocationURI().toString());
									EValidator.Registry.INSTANCE.put(null, new OCLinEcoreEObjectValidator());
									String strSOAMsg = "Pattern validation errors occured in the mapping model "
											+ f.getName();
									infoMapping = new MultiStatus(Activator.PLUGIN_ID, 1, strSOAMsg, null);
									ResourceSet rs1 = new ResourceSetImpl();
									Resource r1 = rs1.getResource(mappingModel, true);
									EObject eObject1 = r1.getContents().get(0);
									Diagnostic dia = Diagnostician.INSTANCE
											.validate(eObject1);
									if (dia.getSeverity() == Diagnostic.ERROR
											|| dia.getSeverity() == Diagnostic.WARNING) {
										EClass eClass = eObject1.eClass();
										EPackage ePackage = eClass.getEPackage();
										String strMsg = "The SCA model has been changed which causes validation errors occurred for the mapping model "
												+ mappingModel.lastSegment().replace(".mapping", "")
												+ " at the mapping file "
												+ f.getName();
										MultiStatus stsInfo = this.getStatus(dia, strMsg);
										infoMapping.add(stsInfo);
									}
									
									//EValidator.Registry.INSTANCE.put(null, new
									//		OCLinEcoreEObjectValidator());
									
									ValidationDetailDialog dialog;
									if (infoMapping.getChildren().length > 0)
									{
										dialog = new ValidationDetailDialog(targetPart.getSite().getShell(), "Validation result", Dialog.getImage(Dialog.DLG_IMG_ERROR), "Errors occurred during validation", infoMapping, Activator.getDefault());
										dialog.open();
									}
									else
									{
										arrPatternViewName.add(mappingModel.lastSegment().replace(".mapping", ""));
										String metaPatternName = getPatternModelURI(
												(IFile) f).lastSegment().replace(
												".soapattern", "");
										URI metaPatternModel = URI
												.createURI(patternViewFolder
														.getLocationURI()
														+ "/"
														+ metaPatternName
														+ "/"
														+ mappingModel
																.lastSegment()
																.replace("mapping",
																		"ecore"));
										URI outputModel = URI
												.createURI(patternViewFolder
														.getLocationURI()
														+ "/"
														+ metaPatternName
														+ "/"
														+ mappingModel
																.lastSegment()
																.replace("mapping",
																		"patternview"));
										// Unregister pattern view package
										EPackage.Registry.INSTANCE
												.remove("http://patternview/1.0");
	
										// Register pattern view package
										ResourceSet rs = new ResourceSetImpl();
										Resource r = rs.getResource(URI
												.createURI(metaPatternModel
														.toString()), true);
										EObject eObject = r.getContents().get(0);
										if (eObject instanceof EPackage) {
											EPackage p = (EPackage) eObject;
											EPackage.Registry.INSTANCE.put(
													p.getNsURI(), p);
										}
	
										// Run Kermeta
										IOConsole console = new EclipseConsole(
												"Kermeta Simulator");
										try {
											String sourcePatternUrl = mappingModel
													.toString();
											String metaPatternUrl = metaPatternModel
													.toString();
											String targetPatternUrl = outputModel
													.toString();
	
											KermetaRunner.Mapping2View(
													sourcePatternUrl,
													metaPatternUrl,
													targetPatternUrl, console);
	
										} catch (Throwable e) {
	
											e.printStackTrace();
										}
										// End Run Kermeta
									}
								}
							}
					}
				} catch (CoreException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

				try {
					myProject.refreshLocal(IResource.DEPTH_INFINITE,
							new NullProgressMonitor());
				} catch (CoreException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				
				//Validation
				EValidator.Registry.INSTANCE.put(null, new OCLinEcoreEObjectValidator());
				
				String strFinalMsg = "Pattern validation errors occured in the SCA model "
						+ inputModelFile.getName();
				MultiStatus finalInfo = new MultiStatus(Activator.PLUGIN_ID, 1, strFinalMsg, null);
				
				try {
					for (IResource folder : patternViewFolder.members()) {
						if (folder instanceof IFolder)
						{
							for (IResource file : ((IFolder) folder).members()) {
								if (file instanceof IFile)
								{
									if (file.getFileExtension().equals("patternview") && arrPatternViewName.contains(file.getName().replace(".patternview","")))
									{
										IFile patternViewFile = (IFile)file;
										URI patternModel = URI.createURI(patternViewFile
												.getLocationURI().toString());
										
										//URI metaPatternModel = URI.createURI(patternModel.toString().replace("patternview", "ecore"));
										URI metaPatternModel = null;
										IFolder patternFolder = (IFolder)patternViewFile.getParent();
										try {
											for (IResource r : patternFolder.members()) {
												if (r instanceof IFile)
												{
													if (r.getFileExtension().equals("ecore"))
														metaPatternModel = URI.createURI(r
																.getLocationURI().toString());
												}
											}
										} catch (CoreException e) {
											// TODO Auto-generated catch block
											e.printStackTrace();
										}
										
										//Unregister pattern view package
										EPackage.Registry.INSTANCE.remove("http://patternview/1.0");
										
										//Register pattern view package
										ResourceSet rs = new ResourceSetImpl();
										Resource r = rs.getResource(URI.createURI(metaPatternModel.toString()), true);
										EObject eObject = r.getContents().get(0);
										if (eObject instanceof EPackage) {
										    EPackage p = (EPackage)eObject;
										    EPackage.Registry.INSTANCE.put(p.getNsURI(), p);
										}
										
										String strSOAMsg = "Pattern validation errors occured in the pattern view model "
												+ patternViewFile.getName();
										MultiStatus info = new MultiStatus(Activator.PLUGIN_ID, 1, strSOAMsg, null);
										
										rs = new ResourceSetImpl();
										r = rs.getResource(patternModel, true);
										eObject = r.getContents().get(0);
										Diagnostic dia = Diagnostician.INSTANCE
												.validate(eObject);
										if (dia.getSeverity() == Diagnostic.ERROR
												|| dia.getSeverity() == Diagnostic.WARNING) {
											EClass eClass = eObject.eClass();
											EPackage ePackage = eClass.getEPackage();
											String strMsg = "Validation errors occurred for the pattern "
													+ metaPatternModel.lastSegment().replace(".ecore", "")
													+ " at the pattern view "
													+ patternViewFile.getName();
											MultiStatus stsInfo = this.getStatus(dia, strMsg);
											info.add(stsInfo);
										}
										if (info.getChildren().length > 0)
											finalInfo.add(info);
									}
								}
							}
						}
					}
				} catch (CoreException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				ValidationDetailDialog dialog;
				if (finalInfo.getChildren().length > 0)
				{
					dialog = new ValidationDetailDialog(targetPart.getSite().getShell(), "Validation result", Dialog.getImage(Dialog.DLG_IMG_ERROR), "Errors occurred during validation", finalInfo, Activator.getDefault());
					dialog.open();
				}
				else if (arrPatternViewName.size() > 0)
				{
					dialog = new ValidationDetailDialog(targetPart.getSite().getShell(), "Validation result", Dialog.getImage(Dialog.DLG_IMG_INFO), "Pattern view validation successfull without any architectural conflict", null, Activator.getDefault());
					dialog.open();
				}
				
			}
		}
	}

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		// TODO Auto-generated method stub
		this.selection = selection;
		action.setEnabled(!selection.isEmpty());
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		// TODO Auto-generated method stub
		this.targetPart = targetPart;
	}

	/**
	 * 
	 * @param mappingFile
	 * @return the corresponding pattern model of a mapping
	 */
	URI getPatternModelURI(IFile mappingFile) {
		// Obtain a new resource set
		ResourceSet resSet = new ResourceSetImpl();
		// Get the resource
		Resource resource = resSet.getResource(
				URI.createURI(mappingFile.getLocationURI().toString()), true);

		// MappingSwitch is used to get the right mapping type according to an
		// object
		soadmanagementSwitch visitor = new soadmanagementSwitch() {
			public URI casePatternMapping(RootMapping object) {
				return null;
			}

			public URI caseCompositeMapping(CompositeMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentMapping(ComponentMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseReferenceMapping(ReferenceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseServiceMapping(ServiceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentReferenceMapping(
					ComponentReferenceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentServiceMapping(
					ComponentServiceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			@Override
			public URI defaultCase(EObject object) {
				return null;
			}
		};

		URI uriPattern = null;
		// Search through the mapping tree, find at least one target general
		// pattern model URI
		for (TreeIterator<Object> iter = EcoreUtil.getAllContents(resource,
				true); iter.hasNext();) {
			EObject eObject = (EObject) iter.next();
			uriPattern = (URI) visitor.doSwitch(eObject);
			if (uriPattern != null)
				break;
		}
		return uriPattern;
	}

	/**
	 * 
	 * @param mappingFile
	 * @return the corresponding simplified SCA model of a mapping
	 */
	URI getSimplifiedSCAModelURI(IFile mappingFile) {
		// Obtain a new resource set
		ResourceSet resSet = new ResourceSetImpl();
		// Get the resource
		Resource resource = resSet.getResource(
				URI.createURI(mappingFile.getLocationURI().toString()), true);

		// MappingSwitch is used to get the right mapping type according to an
		// object
		soadmanagementSwitch visitor = new soadmanagementSwitch() {
			public URI casePatternMapping(RootMapping object) {
				return null;
			}

			public URI caseCompositeMapping(CompositeMapping object) {
				URI uriPattern = object.getSource().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentMapping(ComponentMapping object) {
				URI uriPattern = object.getSource().eResource().getURI();
				return uriPattern;
			}

			public URI caseReferenceMapping(ReferenceMapping object) {
				URI uriPattern = object.getSource().eResource().getURI();
				return uriPattern;
			}

			public URI caseServiceMapping(ServiceMapping object) {
				URI uriPattern = object.getSource().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentReferenceMapping(
					ComponentReferenceMapping object) {
				URI uriPattern = object.getSource().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentServiceMapping(
					ComponentServiceMapping object) {
				URI uriPattern = object.getSource().eResource().getURI();
				return uriPattern;
			}

			@Override
			public URI defaultCase(EObject object) {
				return null;
			}
		};

		URI uriPattern = null;
		// Search through the mapping tree, find at least one target general
		// pattern model URI
		for (TreeIterator<Object> iter = EcoreUtil.getAllContents(resource,
				true); iter.hasNext();) {
			EObject eObject = (EObject) iter.next();
			uriPattern = (URI) visitor.doSwitch(eObject);
			if (uriPattern != null)
				break;
		}
		return uriPattern;
	}
	
	/**
	 * 
	 * @param dia
	 * @param strMsg
	 * @return The status from a diagnostic
	 */
	MultiStatus getStatus(Diagnostic dia, String strMsg) {
		// Walk through all the sub diagnostics and document their messages in
		// the status
		MultiStatus subMultiStatus = new MultiStatus(Activator.PLUGIN_ID, 1,
				strMsg, null);
		;
		for (Iterator<Diagnostic> iterator = dia.getChildren().iterator(); iterator
				.hasNext();) {
			Diagnostic subDia = (Diagnostic) iterator.next();
			Status subStatus = new Status(IStatus.INFO, Activator.PLUGIN_ID, 1,
					subDia.getMessage(), null);
			subMultiStatus.add(subStatus);
		}
		return subMultiStatus;
	}
}
